<?php
class WeChat{
    private $_appid;
    private $_appsecret;
    private $_token;

    public function __construct($appid,$appsecret,$token){
        $this->_appid = $appid;
        $this->_appsecret = $appsecret;
        $this->_token = $token;
    }

    /******************** 模板  ********************/
    private $tpl = array(
        //发送文本消息模板
        'text' => '	<xml>
							<ToUserName><![CDATA[%s]]></ToUserName>
							<FromUserName><![CDATA[%s]]></FromUserName>
							<CreateTime>%s</CreateTime>
							<MsgType><![CDATA[text]]></MsgType>
							<Content><![CDATA[%s]]></Content>
							</xml>',

        //发送图片消息模板
        'image' => '<xml>
							<ToUserName><![CDATA[%s]]></ToUserName>
							<FromUserName><![CDATA[%s]]></FromUserName>
							<CreateTime>%s</CreateTime>
							<MsgType><![CDATA[image]]></MsgType>
							<Image>
							<MediaId><![CDATA[%s]]></MediaId>
							</Image>
							</xml>',
        //发送图文消息模板
        'list' => 	'<xml>
							<ToUserName><![CDATA[%s]]></ToUserName>
							<FromUserName><![CDATA[%s]]></FromUserName>
							<CreateTime>%s</CreateTime>
							<MsgType><![CDATA[news]]></MsgType>
							<ArticleCount>%s</ArticleCount>
							<Articles>
							%s
							</Articles>
							</xml>',
        'item' => 	'<item>
							<Title><![CDATA[%s]]></Title>
							<Description><![CDATA[%s]]></Description>
							<PicUrl><![CDATA[%s]]></PicUrl>
							<Url><![CDATA[%s]]></Url>
							</item>',
        //音乐消息
        'music' => '<xml>
							<ToUserName><![CDATA[%s]]></ToUserName>
							<FromUserName><![CDATA[%s]]></FromUserName>
							<CreateTime>%s</CreateTime>
							<MsgType><![CDATA[music]]></MsgType>
							<Music>
							<Title><![CDATA[%s]]></Title>
							<Description><![CDATA[%s]]></Description>
							<MusicUrl><![CDATA[%s]]></MusicUrl>
							<HQMusicUrl><![CDATA[%s]]></HQMusicUrl>
							<ThumbMediaId><![CDATA[%s]]></ThumbMediaId>
							</Music>
							</xml>'
    );



    /**
     *_request():发出请求
     *@curl:访问的URL
     *@https：安全访问协议
     *@method：请求的方式，默认为get
     *@data：post方式请求时上传的数据
     **/
    private function _request($curl, $https=true, $method='get', $data=null){
        $ch = curl_init();//初始化
        curl_setopt($ch, CURLOPT_URL, $curl);//设置访问的URL
        curl_setopt($ch, CURLOPT_HEADER, false);//设置不需要头信息
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);//只获取页面内容，但不输出
        if($https){
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);//不做服务器认证
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);//不做客户端认证
        }
        if($method == 'post'){
            curl_setopt($ch, CURLOPT_POST, true);//设置请求是POST方式
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);//设置POST请求的数据
        }
        $str = curl_exec($ch);//执行访问，返回结果
        curl_close($ch);//关闭curl，释放资源
        return $str;
    }

    /******************** _getAccesstoken()：获取access token  ********************/
    private function _getAccesstoken(){
        $file = './accesstoken'; //用于保存access token
        if(file_exists($file)){ //判断文件是否存在
            $content = file_get_contents($file); //获取文件内容
            $content = json_decode($content);//json解码
            if(time()-filemtime($file)<$content->expires_in) //判断文件是否过期
                return $content->access_token;//返回access token
        }
        $content = $this->_request("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$this->_appid."&secret=".$this->_appsecret); //获取access token的json对象
        file_put_contents($file, $content); //保存json对象到指定文件
        $content = json_decode($content);//进行json解码
        return $content->access_token;//返回access token
    }

    /**
     *_getTicket():获取ticket，用于以后换取二维码
     *@expires_secords：二维码有效期（秒）
     *@type ：二维码类型（临时或永久）
     *@scene：场景编号
     **/
    public function _getTicket($expires_secords = 604800, $type = "temp", $scene = 1){
        if($type == "temp"){//临时二维码的处理
            $data = '{"expire_seconds":'.$expires_secords.', "action_name": "QR_SCENE", "action_info": {"scene": {"scene_id": '.$scene.'}}}';//临时二维码生成所需提交数据
            return $this->_request("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=".$this->_getAccesstoken(),true, "post", $data);//发出请求并获得ticket
        } else { //永久二维码的处理
            $data = '{"action_name": "QR_LIMIT_SCENE", "action_info": {"scene": {"scene_id": '.$scene.'}}}';//永久二维码生成所需提交数据
            return $this->_request("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=".$this->_getAccesstoken(),true, "post", $data);//发出请求并获得ticket
        }
    }

    /**
     *_getQRCode():获取二维码
     *@expires_secords：二维码有效期（秒）
     *@type：二维码类型
     *@scene：场景编号
     **/
    public function _getQRCode($expires_secords,$type,$scene){
        $content = json_decode($this->_getTicket($expires_secords,$type,$scene));//发出请求并获得ticket的json对象
        $ticket = $content->ticket;//获取ticket
        $image = $this->_request("https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=".urlencode($ticket)
        );//发出请求获得二维码图像
        //$file = "./".$type.$scene.".jpg";// 可以将生成的二维码保存到本地，便于使用
        //file_put_contents($file, $image);//保存二维码
        return $image;
    }

    /****************************** 检查安全性 *******************************/
    public function valid()
    {
        $echoStr = $_GET["echostr"];

        //valid signature , option
        if($this->checkSignature()){
            echo $echoStr;
            exit;
        }
    }


    /****************************** 解析用户上传文本的信息 *******************************/
    public function responseMsg()
    {
        //get post data, May be due to the different environments
        $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];  //获得用户发送信息
        $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);

        /**
         *  根据不同情况 做不同处理 调用不同的方法
         *  并且把得到的内容传过去
         */
        switch($postObj->MsgType){
            case 'event':
                $this->_doEvent($postObj);//事件类型
                break;
            case 'text':
                $this->_doText($postObj);//文本信息
                break;
            case 'image':
                $this->_doImage($postObj);//图片信息
                break;
            case 'voice':
                $this->_doVoice($postObj);//语音信息
                break;
            case 'video':
                $this->_doVideo($postObj);//视频信息
                break;
            case 'location':
                $this->_doLocation($postObj);//地理位置信息
                break;
            case 'link';
                $this->_dolink($postObj);  //链接信息
                break;
            case 'shortvideo';
                $this->_doshortVideo($postObj);//小视频信息
            default: exit;
        }
    }


    /**
     * @param $postObj 关注订阅事件
     */
    private function _doEvent($postObj){ //事件处理
        switch($postObj->Event){
            case  'subscribe': //订阅
                $this->_doSubscribe($postObj);
                break;
            case 'unsubscribe': //取消订阅
                $this->_doUnsubscribe($postObj);
                break;
            case 'CLICK':           //当点击的时候
                $this->_doClick($postObj);
                break;
            default:;
        }
    }
    /****************************** 解析用户上传文本的信息 *******************************/
    public function _doClick($postObj){
        if($postObj->EventKey == 'news'){
            /************************ 这里是存放内容的 之后把内容循环到 $item 里就可以了，循环好吧这个变量替换给“Articles” ******************************/
            $news = array(
                array('title'=>'军媒曝轰6K遭外军战机逼近贴飞：飞行员已能眼神接触',
                       'description'=>'南部战区空军航空兵某团学习党的十九大精神加快转型建设步伐——变革重塑，锻造空中战略铁拳',
                       'picUurl'=>'http://n.sinaimg.cn/mil/crawl/20171024/aEyt-fymzqpq3791880.jpg',
                        'url'=>'http://mil.news.sina.com.cn/china/2017-10-24/doc-ifymzzpw0887156.shtml'
                ),
                array('title'=>'运20终于不用受制于俄：中方披露涡扇18已上机试飞',
                    'description'=>'2016年，国产运20服役，让中国成为世界上第三个可以制造200吨级大型运输机的国家，如今已有多架运20交付部队服役，已发现05号机，实际数量更多。',
                    'picUurl'=>'http://n.sinaimg.cn/mil/crawl/20171024/FK4a-fymzzpw0483560.jpg',
                    'url'=>'http://mil.news.sina.com.cn/jssd/2017-10-24/doc-ifymzzpw0484925.shtml'
                ),
            );
            $count = count($news);
            $it = "";
            for($i=0;$i<count($news);$i++) {
                $it .= sprintf($this->tpl['item'], $news[$i]['title'], $news[$i]['description'], $news[$i]['picUurl'], $news[$i]['url']);
            }
                $content = sprintf($this->tpl['list'], $postObj->FromUserName, $postObj->ToUserName, time(), $count, $it);
                echo $content;

        }

    }


    /**
     * @param $postObj  订阅信息
     *  可以不保存到数据库  个人信息
     */
    private function _doSubscribe($postObj){
        $tpltext = '<xml>
                        <ToUserName><![CDATA[%s]]></ToUserName>
                        <FromUserName><![CDATA[%s]]></FromUserName>
                        <CreateTime>%s</CreateTime>
                        <MsgType><![CDATA[text]]></MsgType>
                        <Content><![CDATA[%s]]></Content>
                    </xml>';
        $str = sprintf($tpltext,$postObj->FromUserName,$postObj->ToUserName,time(),'欢迎您关注 二狗子 的世界！');
        //还可以保存用户的信息到数据库
        echo $str;

    }

    /**
     * @param $postObj 取消订阅信息
     *  取消之后 删除数据库个人信息 不需要发送任何消息 或者不删除 进行标注 表示不关注我的用户
     */
    private function _doUnsubscribe($postObj){
        ;//把用户的信息从数据库中删除
    }

    /****************************** @param $postObj 处理内容文本 *******************************/
    private function _doText($postObj){
        $fromUsername = $postObj->FromUserName;
        $toUsername = $postObj->ToUserName;
        $keyword = trim($postObj->Content);
        $time = time();
        $textTpl = "<xml>
					<ToUserName><![CDATA[%s]]></ToUserName>
					<FromUserName><![CDATA[%s]]></FromUserName>
					<CreateTime>%s</CreateTime>
					<MsgType><![CDATA[%s]]></MsgType>
					<Content><![CDATA[%s]]></Content>
					<FuncFlag>0</FuncFlag>
					</xml>";
        if(!empty( $keyword ))
        {
            $contentStr = "你说的什么，我有点不大明白！";
            if(mb_substr($keyword,0,2,'utf-8') == '歌曲'){       //用中卫字符截取方式
                $this->_doSendMusic($postObj);
            }
//            $data = "chat=".$keyword;
//            $contentStr = $this->_request("http://www.xiaodoubi.com/bot/chat.php",false,"post",$data);
            if($keyword == "hello")
                $contentStr = "Welcome to wechat  PHP 39 world!";
            if($keyword == "PHP")
                $contentStr = "最流行的网页编程语言！";
            if($keyword == "JAVA")
                $contentStr = "较流行的网页编程语言！";

            $msgType = "text";
            $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
            echo $resultStr;
        }
        exit;
    }

    /**
     * @param $postObj 处理图片
     */
    private function _doImage($postObj){
        $tpltext='<xml>
                    <ToUserName><![CDATA[%s]]></ToUserName>
                    <FromUserName><![CDATA[%s]]></FromUserName>
                    <CreateTime>%s</CreateTime>
                    <MsgType><![CDATA[text]]></MsgType>
                    <Content><![CDATA[%s]]></Content>
                 </xml>';

        //$postObj->PicUrl  这里存的是图片的地址
        $str = sprintf($tpltext,$postObj->FromUserName,$postObj->ToUserName,time(),'您发送的图片在'.$postObj->PicUrl."。");
        echo $str;
    }

    private function checkSignature()
    {
        $signature = $_GET["signature"];
        $timestamp = $_GET["timestamp"];
        $nonce = $_GET["nonce"];
        $token = TOKEN;
        $tmpArr = array($token, $timestamp, $nonce);
        sort($tmpArr, SORT_STRING);
        $tmpStr = implode( $tmpArr );
        $tmpStr = sha1( $tmpStr );

        if( $tmpStr == $signature ){
            return true;
        }else{
            return false;
        }
    }

    /****************************** 查询菜单 查询结果直接返回*******************************/
    public  function _queryMenu(){
        $url = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=".$this->_getAccesstoken();
        $menu = $this->_request($url);
        return  $menu;
    }

    /********************************删除菜单  查询结果直接返回 ******************************/
    public  function _deleteMenu(){
        $url = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=".$this->_getAccesstoken();
        $result = $this->_request($url);
        $result = json_decode($result);
        if($result->errcode == 0){
            echo "删除成功！";
        }
    }


    /****************************** 添加菜单 *******************************/
    public function _createMenu($menu){
        $url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=".$this->_getAccesstoken();
        $result = $this->_request($url,true,"post",$menu);
        $result = json_decode($result);
        if($result->errcode == 0){
            echo "菜单创建成功！";
        }
    }

    public function _doLocation($postObj){
        $content = "您所在的位置是经度：".$postObj->Location_Y."，纬度：".$postObj->Location_X;
        $str = sprintf($this->tpl['text'],$postObj->FromUserName,$postObj->ToUserName,time(),$content."。");
        echo $str;
    }
    /****************************** 获取用户 *******************************/
    public function _getUserlist(){
        $url = 'https://api.weixin.qq.com/cgi-bin/user/get?access_token='.$this->_getAccesstoken();
        $cotent = $this->_request($url);
        $cotent = json_decode($cotent);  //返回的是对象
        $user =  $cotent->data->openid;  //这里的user 就是一个数组
        return $user;  //这里还回的是已经解析后的用户列表
        //正确时返回格式：{"total":2,"count":2,"data":{"openid":["","OPENID1","OPENID2"]},"next_openid":"NEXT_OPENID"}；
    }

    /****************************** 发送信息给所有用户 *******************************/
    public function _sendAll($content){
        $tpl = '{
                   "touser":[
                    %s
                   ],
                    "msgtype": "text",
                    "text": { "content": "%s"}
                }';
        $curl = 'https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token='.$this->_getAccesstoken();
        $user = $this->_getUserlist();
        $u = "";                                          //为了把所有的用户放在一起
        for($i=0;$i<count($user);$i++){
                $u .= '"'.$user[$i].'"';                 //这里注意 每个用户俩边都有双引号 逗号也可以这这后面加
            if($i < count($user)-1){                    // 如果$i 小于总数 则在每个用户后面加个逗号
                $u .=',';
            }
        }
        $data = sprintf($tpl,$u,$content);                           //把内容放进去
        $result = $this->_request($curl,true,"post",$data);         //访问这个地址发内容
        $result = json_decode($result);
        if($result->errcode == 0){
            echo "发送成功！";
        }
    }

    /****************************** 新增图片素材 *******************************/
    public function _addMedia($type,$file){
        $url = 'https://api.weixin.qq.com/cgi-bin/media/upload?access_token='.$this->_getAccesstoken().'&type='.$type;
        $data['type'] = $type;
        $data['media'] = '@'.$file;
        $result = $this->_request($url,true,"post",$data);
        echo $result;        //输出成功 一个 json格式
    }

    /****************************** 发送歌曲 *******************************/
    private function _doSendMusic($postObj){
        $mediaId = "hmQEWOHkPFw3QLaP0HBHG4GrWO_SFytnbnDXwgjWQRNQl5ptmj9it-48vsYJRDBQ";
        $content = $postObj->Content;
        $content = mb_substr($content,2,mb_strlen($content,'utf-8')-2,'utf-8');//删除字符串前两个字符（删除”歌曲“）
        $arr = explode('@',$content);//分解歌曲和歌手到数组
        $song = $arr[0];
        $singer = '';
        if(isset($arr[1])){//生成有歌曲和歌手的音乐搜索地址
            $singer = $arr[1];
            $curl = 'http://box.zhangmen.baidu.com/x?op=12&count=1&title='.$arr[0].'$$'.$arr[1].'$$$$';
        }
        else //搜索仅有歌曲的地址
            $curl = 'http://box.zhangmen.baidu.com/x?op=12&count=1&title='.$arr[0].'$$';
        $response = $this->_request($curl, false);//开始搜索
        $res = simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA);//搜索结果解析
        $encode = $res->url->encode;
        $decode = $res->url->decode;
        $musicurl = mb_substr($encode, 0, mb_strrpos($encode, '/', 'utf-8') + 1,'utf-8').mb_substr($decode, 0, mb_strrpos($decode, '&', 'utf-8'),'utf-8');
        file_put_contents('./tmp', mb_substr($encode, 0, mb_strrchr($encode, '/', 'utf-8') + 1,'utf-8'));//生成歌曲的实际地址
        $str = sprintf($this->tpl['music'],$postObj->FromUserName,$postObj->ToUserName,time(),$arr[0],$arr[1],$musicurl,$musicurl,$mediaId);//发送歌曲到用户
        echo $str;
        exit;


    }
}
